home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / PROGENV / Inspector.C < prev    next >
C/C++ Source or Header  |  1992-08-26  |  13KB  |  569 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "ET++.h"
  6.  
  7. #include "Inspector.h"
  8.  
  9. #include "ObjList.h"
  10. #include "OrdColl.h"
  11. #include "Dictionary.h"
  12. #include "ObjectTable.h"
  13. #include "ClassItem.h"
  14. #include "ClassManager.h"
  15. #include "AccessMem.h"
  16. #include "MenuBar.h"
  17. #include "WindowSystem.h"
  18. #include "Buttons.h"
  19. #include "Filler.h"
  20. #include "Math.h"
  21. #include "Fields.h"
  22.  
  23. #include "ObjectView.h"
  24. #include "Reference.h"
  25. #include "InspItem.h"
  26. #include "ClassList.h"
  27. #include "EtPeManager.h"
  28. #include "EtPeCmdNo.h"
  29. #include "EtProgEnv.h"
  30.  
  31. const int cMaxObjects= 400;
  32.  
  33. //---- timeout handler to refresh inspector views ------------------------------
  34.  
  35. class PeRefreshHandler : public SysEvtHandler {
  36.     PeInspector *inspector;
  37. public:
  38.     MetaDef(PeRefreshHandler);
  39.     PeRefreshHandler(PeInspector *w) : SysEvtHandler(0)
  40.     { inspector= w; }
  41.     bool HasInterest(SysEventCodes)
  42.     { return inspector->IsOpen(); }
  43.     void Notify(SysEventCodes, int) 
  44.     { inspector->GetWindow()->UpdateEvent(); }
  45. };
  46.  
  47. NewMetaImpl(PeRefreshHandler, SysEvtHandler, (TP(inspector)));
  48.  
  49. //---- update References to deleted objects
  50.  
  51. void InspectorFreeHook(void*, void *addr, size_t sz)
  52. {
  53.     void *end= (void*)((u_long)addr + sz);
  54.     for (int i= 0; i < PeInspector::allInspectors->Size(); i++) {
  55.     PeInspector *ip= (PeInspector*)PeInspector::allInspectors->At(i);
  56.     if (addr != ip)
  57.         ip->FreedMemory(addr, end);
  58.     }
  59. }
  60.   
  61. //---- FindInspReferences --------------------------------------------------------------
  62.  
  63. class PeFindInspReferences: public AccessObjPtrs {
  64. protected:
  65.     Object *referencesTo;
  66.     PeInspector *ip;
  67. public:
  68.     PeFindInspReferences(PeInspector *insp) : AccessObjPtrs(0)
  69.     { ip= insp; }
  70.     void ReferencesTo(Object *op)
  71.     { referencesTo= op; }
  72.     void FoundPointer(Object*, char*, int, bool);
  73. };    
  74.  
  75. void PeFindInspReferences::FoundPointer(Object *op, char *name, int at, bool)
  76. {
  77.     if (op == referencesTo /* &&  ?? !inObject->IsKindOf(Assoc) */
  78.                         && !inObject->IsKindOf(PeObjectItem))
  79.     ip->FoundReference(inObject, name, at);
  80. }
  81.  
  82. //---- Inspector ----------------------------------------------------------------
  83.  
  84. NewMetaImpl(PeInspector, EtPeTool, (TP(classes), TP(objects), TP(classItems), TP(objectItems),
  85.         TP(references), TP(referenceItems), TP(refTitle), TP(objTitle)));
  86.  
  87. PeInspector *PeInspector::inspector;
  88. int PeInspector::inspcnt;
  89. OrdCollection *PeInspector::allInspectors;
  90.  
  91. PeInspector::PeInspector(Manager *m) : EtPeTool(m, "Inspector")
  92. {
  93. }
  94.  
  95. PeInspector::~PeInspector()
  96. {
  97.     allInspectors->RemovePtr(this);
  98.     if (allInspectors->Size() == 0) {
  99.     Storage::SetFreeHook(0, 0);
  100.     SafeDelete(allInspectors);
  101.     }
  102.     if (refresh) {
  103.     refresh->Remove();
  104.     refresh= 0;
  105.     }
  106.     SafeDelete(objView);
  107.     SafeDelete(findReferences);
  108.     SafeDelete(classes);
  109.     SafeDelete(objects);
  110.     SafeDelete(references);
  111.     //SafeDelete(refTitle);
  112.     if (path) {
  113.     path->FreeAll();
  114.     SafeDelete(path);
  115.     }
  116.     //SafeDelete(objTitle);
  117. }
  118.  
  119. VObject *PeInspector::DoMakeContent()
  120. {
  121.     findReferences= new PeFindInspReferences(this); 
  122.     
  123.     classes= new PeClassListView(this, TRUE);
  124.     
  125.     objTitle= new TextField(cIdNone, 20, gFixedFont->WithFace(eFaceItalic));
  126.     objTitle->SetEditable(FALSE);
  127.     objects= new CollectionView(this, 0, eCVDefault);
  128.     objects->SetMinExtent(Point(400, 0));
  129.     ResetObjects();
  130.     objects->SetId(cIdObjects);
  131.     
  132.     refTitle= new TextField(cIdNone, 20, gFixedFont->WithFace(eFaceItalic));
  133.     refTitle->SetEditable(FALSE);
  134.     references= new CollectionView(this, 0, eCVDefault, 0);
  135.     references->SetMinExtent(Point(400, 0));
  136.     ResetReferences();
  137.     references->SetId(cIdReferences);   
  138.     
  139.     objView= new PeObjectView();
  140.     objView->SetNextHandler(this);
  141.     SetFirstHandler(objView);
  142.     
  143.     VObject *classScroller= new Scroller(classes, Point(-1, 100));
  144.     classScroller->SetFlag(eVObjHFixed | eVObjVFixed);
  145.     AddKeySelectItem(classScroller);
  146.  
  147.     VObject *w=
  148.     new VExpander(gPoint2,
  149.         new HBox(gPoint2, (VObjAlign)(eVObjVEqual|eVObjHExpand),
  150.         classScroller,
  151.         new VExpander(gPoint2,
  152.             objTitle,
  153.             new Scroller(objects, gPoint0, cIdNone, eScrollRight),
  154.             0
  155.         ),
  156.         new VExpander(gPoint2,
  157.             refTitle,
  158.             new Scroller(references, gPoint0, cIdNone, eScrollRight),
  159.             0
  160.         ),
  161.         0
  162.         ),
  163.         new HExpander(gPoint8,
  164.         start= new ActionButton(cIdShiftStart, "||<"), 
  165.          left= new ActionButton(cIdShiftLeft,  "<<"), 
  166.                new ActionButton(cIdShiftAppl,  "Appl"), 
  167.         right= new ActionButton(cIdShiftRight, ">>"), 
  168.           end= new ActionButton(cIdShiftEnd,   ">||"), 
  169.         0
  170.         ),
  171.         new HExpander(gPoint2, new Scroller(objView, Point(550, 300)), 0),
  172.         0
  173.     );
  174.     
  175.     path= new OrdCollection;
  176.     if (allInspectors == 0) {
  177.     allInspectors= new OrdCollection;
  178.     Storage::SetFreeHook(InspectorFreeHook, 0);
  179.     }
  180.     allInspectors->Add(this);
  181.     
  182.     UpdateButtons();
  183.  
  184.     position= -1;
  185.     gSystem->AddTimeoutHandler(refresh= new PeRefreshHandler(this));
  186.     
  187.     return w;
  188. }
  189.  
  190. MenuBar *PeInspector::DoMakeMenuBar()
  191. {
  192.     MenuBar *mb= EtPeTool::DoMakeMenuBar();
  193.     
  194.     Menu *m= new Menu("Classes");
  195.     m->AppendItems( "Update List",          cUPDATELIST,
  196.             "Hide Empty",           cEMPTYCLASSES, 
  197.             "Edit Definition",      cEDITDECL,
  198.             "Edit Implementation",  cEDITIMPL,
  199.             0);
  200.     mb->AddMenu(m);
  201.     
  202.     m= new Menu("Objects");
  203.     m->AppendItems( "All Instances",        cSHOWALL,
  204.             "References",          cOBJREFERENCES,
  205.             "Object View",        cABSTRVIEW,
  206.             "Object Structure",     cOBJBROWSER,
  207.             0);
  208.     mb->AddMenu(m);
  209.  
  210.     return mb;
  211. }
  212.  
  213. void PeInspector::Init(Object *op)
  214. {
  215.     Push(new Ref(*op));
  216. }
  217.  
  218. void PeInspector::MoveTo(int pos)
  219. {
  220.     pos= Math::Range(0, path->Size() - 1, pos);
  221.     if (pos == position)
  222.     return;
  223.     position= pos;
  224.     Ref *r= (Ref*)path->At(position);
  225.     objView->SetInspected(r);
  226.     ShowReference(r);
  227.     UpdateButtons(); 
  228. }
  229.  
  230. void PeInspector::Push(Ref *r)
  231. {
  232.     if (position != path->Size() - 1)
  233.     while(path->Size() > position+1) {
  234.         Object *tmp= path->RemoveLast();
  235.         if (tmp)
  236.         delete tmp;
  237.     }
  238.  
  239.     int i= path->IndexOf(r);
  240.  
  241.     if (i < 0)
  242.     path->Add(new Ref(*r));
  243.     else {
  244.     while(path->Size() > i+1) {
  245.         Object *tmp= path->RemoveLast();
  246.         if (tmp)
  247.         delete tmp;
  248.     }
  249.     }
  250.  
  251.     objView->SetInspected(r);
  252.     ShowReference(r);
  253.     position= path->Size() - 1;
  254.     UpdateButtons();
  255. }
  256.  
  257. void PeInspector::ShowReference(Ref *ref)
  258. {
  259.     Class *cl= 0;
  260.     Object *op;
  261.     
  262.     if (op= ref->GetObject())
  263.     cl= op->IsA();
  264.     else {
  265.     Reset();
  266.     return;
  267.     }
  268.     ShowClass(cl); 
  269.     ShowObject((Object*)ref->GetBase());   
  270. }
  271.  
  272. void PeInspector::ShowClass(Class *cl)
  273. {   
  274.     if (classes->SelectClass(cl)) 
  275.     LoadObjectsOfClass(cl, TRUE);
  276. }
  277.  
  278. void PeInspector::ShowObject(Object *op)
  279. {   
  280.     PeObjectItem *oi;
  281.     Iter next(objectItems);
  282.     for (int i= 0; oi= (PeObjectItem*)next(); i++) {
  283.     if (oi->GetObject() == (Object*)op) {
  284.         SelectAndRevealItem(objects, i); 
  285.         return;
  286.     }        
  287.     }
  288.     objects->ClearSelection();
  289. }
  290.  
  291. void PeInspector::SelectAndRevealItem(CollectionView *cv, int at)
  292. {
  293.     Rectangle sr(0, at, 1, 1);
  294.     cv->SetSelection(sr);
  295.     Rectangle r(cv->ItemRect(sr));
  296.     //r.extent.x= 1;  // reveal left most pixels
  297.     //cv->RevealRect(r, r.extent);
  298.     cv->RevealAlign(r);
  299. }
  300.  
  301. void PeInspector::UpdateButtons()
  302. {
  303.     start->Enable(position != 0);
  304.     left->Enable(position != 0);
  305.     bool b= position == path->Size() - 1;
  306.     right->Enable(!b);
  307.     end->Enable(!b);
  308. }
  309.  
  310. void PeInspector::LoadObjectsOfClass(Class *cl, bool members)
  311. {    
  312.     int i;
  313.     objectItems= new ObjList;
  314.     
  315.     {
  316.     Object *op;
  317.     ObjectTableIter next(cl, members);
  318.     
  319.     for (i= 0; op= next(); i++) {
  320.         objectItems->Add(new PeObjectItem(cIdNone, op));
  321.         if (i == cMaxObjects) {
  322.         VObject *vop= new TextItem("...", gFixedFont->WithFace(eFaceItalic));
  323.         vop->Disable();
  324.         objectItems->Add(vop);
  325.         break;
  326.         }
  327.     }
  328.     }
  329.     objTitle->SetFString(TRUE, "%d instance%s", i, (i > 1) ? "s" : "");
  330.     objects->SetCollection(objectItems, TRUE);
  331.     objects->Update();    
  332. }
  333.  
  334. void PeInspector::Control(int id, int what, void *data)
  335. {
  336.     PeObjectItem *oi;
  337.     Rectangle r;
  338.  
  339.     switch (id) {
  340.     
  341.     case cIdShiftAppl:
  342.     Push(new Ref(*gApplication));
  343.     break;
  344.     
  345.     case cIdShiftLeft:
  346.     MoveTo(position-1);
  347.     break;
  348.     
  349.     case cIdShiftRight:
  350.     MoveTo(position+1);
  351.     break;
  352.  
  353.     case cIdShiftStart:
  354.     MoveTo(0);
  355.     break;
  356.     
  357.     case cIdShiftEnd:
  358.     MoveTo(path->Size()-1);
  359.     break;
  360.  
  361.     case cIdObjects:
  362.     r= objects->GetSelection();
  363.     if (r.IsEmpty())
  364.         return;
  365.     oi= (PeObjectItem*) objectItems->At(r.origin.y);
  366.     
  367.     if (oi == 0 || !oi->IsKindOf(PeObjectItem))
  368.         return;
  369.     DoInspect(oi->GetObject());
  370.     references->ClearSelection();
  371.     break;
  372.     
  373.     case cIdReferences:
  374.     r= references->GetSelection();
  375.     if (r.IsEmpty())
  376.         return;
  377.     oi= (PeObjectItem*) referenceItems->At(r.origin.y);
  378.     
  379.     if (oi == 0 || !oi->IsKindOf(PeObjectItem))
  380.         return;
  381.     DoInspect(oi->GetObject());
  382.     break;
  383.  
  384.     default:
  385.         switch(what) {
  386.         case cPeCLChangedClass:
  387.         LoadObjectsOfClass((Class*)data, TRUE);
  388.         references->ClearSelection();
  389.         break;
  390.         case cPeLoadRef: 
  391.         Push((Ref*)data);
  392.         break;
  393.         case cPeLoadRefNew:
  394.         Control(cPeInspector, cPeSpawnInsp, (Ref*)data);
  395.         break;
  396.     }
  397.     EtPeTool::Control(id, what, data);    
  398.     break;
  399.     }    
  400. }
  401.  
  402. void PeInspector::DoInspect(Object *op)
  403. {
  404.     if (!ObjectTable::PtrIsValid(op))
  405.     ShowAlert(eAlertNote, "instance 0x%x disappeard", op);
  406.     else if (strcmp(op->ClassName(), "InspectorItem") == 0) // hack
  407.     ShowAlert(eAlertNote, "would crash the inspector");    
  408.     else
  409.     Push(new Ref(*op));
  410. }
  411.  
  412. void PeInspector::ResetReferences()
  413. {
  414.     referenceItems= new OrdCollection(10);
  415.     refTitle->SetString("References", TRUE);
  416.     references->SetCollection(referenceItems, TRUE);
  417. }
  418.  
  419. void PeInspector::ResetObjects()
  420. {
  421.     objTitle->SetString("Number of instances", TRUE);
  422.     objectItems= new ObjList(); 
  423.     objects->SetCollection(objectItems, TRUE);
  424. }
  425.  
  426. void PeInspector::Reset()
  427. {
  428.     objects->ClearSelection();
  429.     classes->ClearSelection();
  430. }
  431.  
  432. void PeInspector::References(Object *op)
  433. {
  434.     referenceItems= new OrdCollection(10);
  435.     refTitle->SetString(form("References to 0x%x (%s)", (int)op, op->ClassName()), TRUE);
  436.     findReferences->ReferencesTo(op);
  437.     {
  438.     ObjectTableIter next(0);
  439.     while (currentOp= next()) {
  440.         findReferences->ForObject(currentOp);
  441.         currentOp->IsA()->EnumerateMembers(findReferences); 
  442.     } 
  443.     }
  444.     references->SetCollection(referenceItems, TRUE);
  445. }
  446.  
  447. void PeInspector::FoundReference(Object *op, char *name, int index)
  448. {
  449.     char *cp;
  450.     if (index == -1)
  451.     cp= form("%s.%s", op->ClassName(), name);
  452.     else
  453.     cp= form("%s.%s[%d]", op->ClassName(), name, index);     
  454.     referenceItems->Add(new PeObjectItem(cp, op));
  455. }
  456.  
  457. Command *PeInspector::DoMenuCommand(int cmd)
  458. {   
  459.     Object *insp= objView->GetInspected()->GetObject();
  460.     
  461.     switch (cmd) {
  462.    
  463.     case cSHOWALL:
  464.     ShowAllInstances();
  465.     break;
  466.     
  467.     case cUPDATELIST:
  468.     classes->LoadClasses();
  469.     ResetObjects();
  470.     break;
  471.     
  472.     case cEMPTYCLASSES:
  473.     classes->ToggleHideEmpty();
  474.     ResetObjects();
  475.     break;
  476.  
  477.     case cOBJREFERENCES:
  478.     References(insp);
  479.     break;
  480.     
  481.     case cPRINT:
  482.     objView->Print();
  483.     break;
  484.  
  485.     case cSPAWN:
  486.     Control(cPeInspector, cPeSpawnInsp, objView->GetInspected());
  487.     break;
  488.  
  489.     case cEDITDECL:
  490.     case cEDITIMPL:
  491.     insp->EditSource(cmd == cEDITDECL);
  492.     break;
  493.     
  494.     case cOBJBROWSER:
  495.     Control(cPeInspector, cPeShowOBrowser, insp);
  496.     break;
  497.     default:
  498.     return EtPeTool::DoMenuCommand(cmd); 
  499.     }
  500.     return gNoChanges; 
  501. }
  502.  
  503. void PeInspector::ShowAllInstances()
  504. {
  505.     Class *cl= classes->SelectedClass();
  506.     if (cl != 0)
  507.     LoadObjectsOfClass(cl, FALSE);
  508. }
  509.    
  510. void PeInspector::DoSetupMenu(Menu *menu)
  511. {
  512.     EtPeTool::DoSetupMenu(menu);
  513.     Class *cl= classes->SelectedClass();
  514.     if (cl) {
  515.     menu->EnableItems(cSHOWALL, cEDITDECL, cEDITIMPL, 0);
  516.     menu->ReplaceItem(cEDITDECL, form("Edit Definition of \"%s\"", cl->Name()));
  517.     menu->ReplaceItem(cEDITIMPL, form("Edit Implementation of \"%s\"", cl->Name()));
  518.  
  519.     }
  520.     menu->ToggleItem(cEMPTYCLASSES, classes->HideEmptyClasses(), 
  521.                "Show All Classes", "Hide Classes with no Instances");
  522.     menu->EnableItems(cUPDATELIST, cEMPTYCLASSES, cPRINT, 0);
  523. }
  524.  
  525. void PeInspector::FreedMemory(void *addr, void *end)
  526. {
  527.     Ref *r= objView->GetInspected();
  528.     u_int base;
  529.     if (r) {
  530.     base= (u_int)r->Addr();
  531.     if (base >= (u_int)addr && base < (u_int)end) 
  532.         objView->InspectedDied();
  533.     }
  534.     if (path->Size() == 0)
  535.     return;
  536.     for (int i= 0; i < path->Size(); i++) {
  537.     r= (Ref*)path->At(i);
  538.     base= (u_int)r->Addr();
  539.     if (base >= (u_int)addr && base < (u_int)end) 
  540.         RemoveDeletedRef(i, r);
  541.     }
  542. }
  543.         
  544. void PeInspector::RemoveDeletedRef(int i, Ref *r)
  545. {
  546.     if (i <= position)
  547.     position= Math::Max(0, position -1);
  548.     path->RemovePtr(r);
  549.     UpdateButtons();    
  550. }
  551.  
  552. void PeInspector::Spawn(Manager *m, Ref *ref, bool)
  553. {
  554.     PeInspector *ip= new PeInspector(m);
  555.     ip->SetOnDismiss(eMgrClose);
  556.     ip->Show();
  557.     ip->Push(ref);
  558. }
  559.  
  560. void PeInspector::ShowObject(Manager *m, Object *op, bool)
  561. {
  562.     if (inspector == 0)
  563.     inspector= new PeInspector(m);
  564.     inspector->Show();
  565.     inspector->Push(new Ref(*op));
  566. }
  567.  
  568.  
  569.